


#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <left4dhooks>
#include <adminmenu>

TopMenu hTopMenu;
TopMenuObject adminkillToTopMenu = INVALID_TOPMENUOBJECT;


#define PLUGIN_NAME                   "l4d2_Player_flight"    //这里写插件名字
#define PLUGIN_AUTHOR                 "豆瓣酱な"                         //作者
#define PLUGIN_DESCRIPTION            "幸存者和特感按R键飞行"   //介绍
#define PLUGIN_VERSION                "1.0"
#define PLUGIN_URL                    "https://gitee.com/sweet-and-sour-bombs"  //网站

public Plugin myinfo =
{
    name        = PLUGIN_NAME,
    author      = PLUGIN_AUTHOR,
    description = PLUGIN_DESCRIPTION,
    version     = PLUGIN_VERSION,
    url         = PLUGIN_URL
}

#define MOVETYPE_WALK 2
#define MOVETYPE_FLYGRAVITY 5
#define MOVECOLLIDE_DEFAULT 0
#define MOVECOLLIDE_FLY_BOUNCE 1


Handle  FlySpeed, MaxSpeed;

bool Flying[MAXPLAYERS+1], BlockSpawn[MAXPLAYERS+1];

ConVar hCvar_DmgEnable;
int g_DmgEnable;

float g_fFlySpeed = 50.0, g_fMaxSpeed = 500.0;

public void OnPluginStart()
{

	hCvar_DmgEnable = CreateConVar("l4d2_Player_flight", "0", "玩家飞行能力. 0=关闭, 1=开启", FCVAR_NOTIFY, true, 0.0, true, 1.0);	
	FlySpeed = CreateConVar("l4d2_Player_fly_speed", "50", "玩家飞行速度", FCVAR_NOTIFY, true, 0.0);
	MaxSpeed = CreateConVar("l4d2_Player_max_speed", "500", "玩家飞行最高速度", FCVAR_NOTIFY, true, 300.0);
	CreateConVar("l4d2_Player_fly_version", PLUGIN_VERSION, "插件版本", FCVAR_NOTIFY);



	HookConVarChange(hCvar_DmgEnable, eConvarChanged);	
	HookConVarChange(FlySpeed, OnFlySpeedChanged);
	HookConVarChange(MaxSpeed, OnMaxSpeedChanged);




	g_fFlySpeed = GetConVarFloat(FlySpeed);
	g_fMaxSpeed = GetConVarFloat(MaxSpeed);
	

	//AutoExecConfig(true, "l4d2_Player_flight");

}

public void OnMapStart()
{
	CvarsChanged();
}

public void eConvarChanged(Handle hCvar, const char[] sOldVal, const char[] sNewVal)
{
	CvarsChanged();
}

void CvarsChanged()
{
	g_DmgEnable = hCvar_DmgEnable.IntValue;

}

//----------------------------------------------------------------admin面板-----------
public void OnAdminMenuReady(Handle aTopMenu)
{
	TopMenu topmenu = TopMenu.FromHandle(aTopMenu);

	if (topmenu == hTopMenu)
		return;
	
	hTopMenu = topmenu;
	
	TopMenuObject objDifficultyMenu = FindTopMenuCategory(hTopMenu, "OtherFeatures");  //OtherFeatures 改成别的名字和下面同一个名字
	if (objDifficultyMenu == INVALID_TOPMENUOBJECT)
		objDifficultyMenu = AddToTopMenu(hTopMenu, "OtherFeatures", TopMenuObject_Category, AdminMenuHandler, INVALID_TOPMENUOBJECT);  //OtherFeatures 改成别的名字和上面同一个名字
	
	adminkillToTopMenu= AddToTopMenu(hTopMenu,"sm_sky",TopMenuObject_Item,adminkillMenuHandler,objDifficultyMenu,"sm_sky",ADMFLAG_ROOT);  //飞天代码
}

public void AdminMenuHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
	if (action == TopMenuAction_DisplayTitle)
	{
		Format(buffer, maxlength, "选择功能:", param);
	}
	else if (action == TopMenuAction_DisplayOption)
	{
		Format(buffer, maxlength, "其它功能", param); //改成你需要的菜单名字
	}
}

public void adminkillMenuHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
{
	if (action == TopMenuAction_DisplayOption)
	{
		if (object_id == adminkillToTopMenu)
			Format(buffer, maxlength, "玩家按R键飞天", param);   //改插件名字
	}
	else if (action == TopMenuAction_SelectOption)
	{
		if (object_id == adminkillToTopMenu)
			DisplayIAConfigMenu(param, 0);  //这里改
	}
}

public void DisplayIAConfigMenu(int client, int item)
{
	char name[64];
	Menu menu = new Menu(MenuHandler_IAConfigMenu);
	menu.SetTitle("玩家按R键飞天配置选项");

	Format(name, sizeof(name), "[%s]玩家按R键飞天", g_DmgEnable ? "关闭" : "开启");
	menu.AddItem("a", name);



	menu.ExitBackButton = true;
	menu.DisplayAt(client, item, MENU_TIME_FOREVER);
}

public int MenuHandler_IAConfigMenu(Menu menu, MenuAction action, int client, int param2)
{
	switch (action)
	{
		case MenuAction_Select:
		{
			char item[16];
			menu.GetItem(param2, item, sizeof item);
			switch(item[0])
			{
				case 'a':
				{
					if (g_DmgEnable)
					{
						hCvar_DmgEnable.IntValue = 0;
						PrintToChat(client, "\x04[提示]\x05玩家按\x03R键\x05飞天已\x03关闭\x05.");
					}
					else
					{
						hCvar_DmgEnable.IntValue = 1;
						PrintToChat(client, "\x04[提示]\x05玩家按\x03R键\x05飞天已\x03开启\x05.");
					}
				}
			}
			DisplayIAConfigMenu(client, menu.Selection);
		}
		case MenuAction_Cancel:
		{
			if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
				DisplayTopMenu(hTopMenu, client, TopMenuPosition_LastCategory);
		}
		case MenuAction_End:
			delete menu;
	}
	return 0;	
}




public void OnFlySpeedChanged(Handle cvar, const char[] oldVal, const char[] newVal)
{
	g_fFlySpeed = StringToFloat(newVal);
}

public void OnMaxSpeedChanged(Handle cvar, const char[] oldVal, const char[] newVal)
{
	g_fMaxSpeed = StringToFloat(newVal);
}

public void OnClientConnected(int client)
{
	Flying[client] = false;
	BlockSpawn[client] = false;
}

// moving this outside of to save initialization
bool elig;

public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon)
{


	if (g_DmgEnable)
	{
		elig = !IsFakeClient(client);
		
		// If we are spawn blocking, and we are either not eligible or we're on the ground, unblock spawn
		if (BlockSpawn[client] && (!elig || GetEntProp(client, Prop_Send, "m_fFlags") & FL_ONGROUND))
		{
			BlockSpawn[client] = false;
		}
		
		if (elig && BlockSpawn[client])
		{
			buttons &= ~IN_ATTACK;
		}
		
		if (elig && buttons & IN_RELOAD)
		{

			if (Flying[client]) KeepFlying(client);
			else StartFlying(client);

		}
		else if (Flying[client]) StopFlying(client);
	}
	return Plugin_Continue;
}

public Action StartFlying(int client)
{
	Flying[client]=true;
	if (g_DmgEnable && !GetAdminFlag(GetUserAdmin(client), Admin_Root)) BlockSpawn[client] = true;
	SetMoveType(client, MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE);
	AddVelocity(client, g_fFlySpeed);
	return Plugin_Continue;
}

public Action KeepFlying(int client)
{
	AddVelocity(client, g_fFlySpeed);
	return Plugin_Continue;
}

public Action StopFlying(int client)
{
	Flying[client]=false;
	SetMoveType(client, MOVETYPE_WALK, MOVECOLLIDE_DEFAULT);
	return Plugin_Continue;
}

void AddVelocity(int client, float speed)
{
	float vecVelocity[3];
	GetEntityVelocity(client, vecVelocity);
	vecVelocity[2] += speed;
	if ((vecVelocity[2]) > g_fMaxSpeed) vecVelocity[2] = g_fMaxSpeed;

	TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vecVelocity);
}

stock void GetEntityVelocity(int entity, float fVelocity[3])
{
    GetEntPropVector(entity, Prop_Data, "m_vecVelocity", fVelocity);
}  

void SetMoveType(int client, int movetype, int movecollide)
{
	SetEntProp(client, Prop_Send, "movecollide", movecollide);
	SetEntProp(client, Prop_Send, "movetype", movetype);
}












